#include "base.h"
#include "rsakeygen.h"
#include "randomnumber.h"

void RsaKeyGen::Generate_RSA(string privatefile, string publicfile, int nbits)
{
  mpz_t * P, *p, *Q, *q, *N, *g, *e, *d, *phi;
  P = Memreuse::New();
  p = Memreuse::New();
  Q = Memreuse::New();
  q = Memreuse::New();
  N = Memreuse::New();
  g = Memreuse::New();
  e = Memreuse::New();
  d = Memreuse::New();
  phi = Memreuse::New();

  GenerateStrongPrime(P, p, nbits/2);
  GenerateStrongPrime(Q, q, nbits/2+1); // so that P*Q=nbits

  mpz_mul(*N, *P, *Q);
  mpz_sub_ui(*P, *P, 1);
  mpz_sub_ui(*Q, *Q, 1);
  mpz_mul(*phi, *P, *Q);

/* Get e like declared in header file, normally 3, 17, 65537 */
  mpz_set_ui(*e, 3);

  mpz_invert(*d, *e, *phi);
  /////test
  mpz_t * test = Memreuse::New();
  mpz_set_ui(*test, 100);
  mpz_powm(*test,*test, *e, *N);
  mpz_powm(*test,*test, *d, *N);
  gmp_printf("%Zx\n", *test);
  ///////test
  RandomNumber rand;
  rand.Initialize(nbits);
  rand.Get_Z_Range(g, N);
  mpz_mul(*g, *g, *g);
  mpz_mod(*g, *g, *N);

  FILE * outfile;
  outfile = fopen(privatefile.c_str(), "w+");
  gmp_fprintf(outfile, "d=%Zx\n", *d);
  gmp_fprintf(outfile, "N=%Zx\n", *N);
  fclose(outfile);

  outfile = fopen(publicfile.c_str(), "w+");
  gmp_fprintf(outfile, "e=%Zx\n", *e);
  gmp_fprintf(outfile, "N=%Zx\n", *N);
  gmp_fprintf(outfile, "g=%Zx\n", *g);
  fclose(outfile);
}

//Q=2q+1 and Q has nbits
void RsaKeyGen::GenerateStrongPrime(mpz_t * Q, mpz_t * q, int nbits)
{
  printf("generating Strong Prime\n");

  RandomNumber rand;
  rand.Initialize(nbits);
  do
    {
	  rand.Get_Z_Bits(q, nbits-1);
    }
  while ( !mpz_tstbit(*q, nbits - 2) );

  do
    {
      GenerateNextPrime(q, q);
	  mpz_mul_ui(*Q, *q, 2);
	  mpz_add_ui(*Q, *Q, 1);
    }while (!mpz_probab_prime_p(*Q, 10));
  printf("Q generated\n");
}



void RsaKeyGen::GenerateNextPrime(mpz_t * nextprime, mpz_t * pos)
{
  mpz_nextprime(*nextprime, *pos);

  while( !mpz_probab_prime_p(*nextprime, 10) );
	{
	  mpz_set(*pos, *nextprime);
	  mpz_nextprime(*nextprime, *pos);
	}
}
